#ifndef QUOTE_H
#define QUOTE_H

#include <string>
#include <iostream>


class Quote
{
public:
    Quote() = default;
    Quote(const std::string &book, double sales_price) :
        bookNo(book), price(sales_price) { }
    Quote(const Quote&) = default;  // 对成员依次拷贝
    Quote(const Quote&&) = default; // 对成员依次移动
    Quote& operator =(const Quote&) = default;  // 拷贝赋值
    Quote& operator =(Quote&&) = default;   // 移动赋值
    std::string isbn() const { return bookNo; }
    // 返回给定数量的书籍的销售总额
    // 派生类负责改写并使用不同的折扣计算算法
    virtual double net_price(std::size_t n) const { return n * price; }
    // 该虚函数返回当前对象的一份动态分配的拷贝
    // 这些成员使用的引用限定符参见 13.6.3 节
    virtual Quote* clone() const & { return new Quote(*this); }
    virtual Quote* clone() && { return new Quote(std::move(*this)); }
    virtual ~Quote() = default; // 对析构函数进行动态绑定
private:
    std::string bookNo; // 书籍的 ISBN 编号
protected:
    double price = 0.0; // 代表普通状态下不打折的价格
};

// 用于保存折扣值和购买量的类,派生类使用这些数据可以实现不同的价格策略
class Disc_quote : public Quote {
public:
    Disc_quote() = default;
    Disc_quote(const std::string &book, double price,
               std::size_t qty, double disc) :
        Quote(book, price), quantity(qty), discount(disc) { }
    double net_price(std::size_t) const = 0;
    std::pair<std::size_t, double> discount_policy() const
        { return {quantity, discount}; }
protected:
    std::size_t quantity = 0;   // 折扣适用的购买量
    double discount = 0.0;      // 表示折扣的小数值
};

// 当同一书籍的销售量超过某个值时启用折扣
// 折扣的值是一个小于 1 的正的小数值，以此来降低正常销售价格
class Bulk_quote : public Disc_quote {
public:
    Bulk_quote() = default;
    Bulk_quote(const std::string& book, double price,
               std::size_t qty, double disc) :
        Disc_quote(book, price, qty, disc) { }
    // 覆盖基类的函数版本以实现基于大量购买的折扣政策
    double net_price(std::size_t) const override;
    Bulk_quote* clone() const & { return new Bulk_quote(*this); }
    Bulk_quote* clone() && { return new Bulk_quote(std::move(*this)); }
private:
    std::size_t min_qty = 0;    // 适用于折扣政策的最低购买量
    double discount = 0.0;      // 以小数表示折扣
};

double print_total(std::ostream&, const Quote&, size_t);

#endif // QUOTE_H
